#include "stm32f10x_gpio.h"
#include "Key_Control.h"
#include "delay.h"
#include "Time_Show.h"
#include "usart.h"
#include "Time2.h"
#include "main.h"
/*
0 正常模式，计时显示
1 修改模式，修改显示
*/

uint8_t key_A_num;
extern uint8_t flash_flag;
extern uint8_t add_flag;

void KEY_GPIO_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStruct;
	//初始化时钟
	RCC_APB2PeriphClockCmd(KEY_A_RCC_PORT|KEY_B_RCC_PORT, ENABLE);
    
	//初始化引脚模式
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStruct.GPIO_Pin = KEY_A_GPIO_PIN;
	GPIO_Init(KEY_A_GPIO, &GPIO_InitStruct);
    
	//初始化引脚模式
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStruct.GPIO_Pin = KEY_B_GPIO_PIN;
	GPIO_Init(KEY_B_GPIO, &GPIO_InitStruct);
    
}


/**
KEY:PA0，EXTI0
1.NVIC中断配置
2.按键GPIO配置
3.中断配置
4.关联中断

键A设置为下降沿动作---外部中断
键B直接扫描电平，不用中断

*/
void EXTI_KEY_Init(void)
{
	NVIC_InitTypeDef NVIC_InitStruct;
	EXTI_InitTypeDef EXTI_InitStruct;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);//开AFIO时钟，外部中断寄存器，复用为中断
    
	/*键A*/
    
    /*NVIC中断配置*/
	NVIC_InitStruct.NVIC_IRQChannel = KEY_A_IRQn;/*外部中断线0*/
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2;
	NVIC_InitStruct.NVIC_IRQChannelSubPriority = 2;
	NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStruct);
	/*2.按键GPIO配置*/
	
	/*3.中断配置*/
	EXTI_InitStruct.EXTI_Line = KEY_A_EXTI_Line;/*外部中断线0*/
	EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
	EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Falling;
	EXTI_InitStruct.EXTI_LineCmd = ENABLE;
	EXTI_Init(&EXTI_InitStruct);
	/*4.关联中断*/
	GPIO_EXTILineConfig(KEY_A_GPIO_Port_Sources, KEY_A_GPIO_Pin_sources);/*外部中断线0*/
    
    /*键B*/
    
    /*NVIC中断配置*/
	NVIC_InitStruct.NVIC_IRQChannel = KEY_B_IRQn;/*外部中断线0*/
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2;
	NVIC_InitStruct.NVIC_IRQChannelSubPriority = 2;
	NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStruct);
	/*2.按键GPIO配置*/
	
	/*3.中断配置*/
	EXTI_InitStruct.EXTI_Line = KEY_B_EXTI_Line;/*外部中断线0*/
	EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
	EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising_Falling;
	EXTI_InitStruct.EXTI_LineCmd = DISABLE;
	EXTI_Init(&EXTI_InitStruct);
	/*4.关联中断*/
	GPIO_EXTILineConfig(KEY_B_GPIO_Port_Sources, KEY_B_GPIO_Pin_sources);/*外部中断线0*/
}


void Exti0_Enable()
{
    EXTI_InitTypeDef EXTI_InitStruct;
	EXTI_InitStruct.EXTI_Line = KEY_A_EXTI_Line;/*外部中断线0*/
	EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
	EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Falling;
	EXTI_InitStruct.EXTI_LineCmd = ENABLE;
	EXTI_Init(&EXTI_InitStruct);
}


void Exti0_Disable()
{
    EXTI_InitTypeDef EXTI_InitStruct;
	EXTI_InitStruct.EXTI_Line = KEY_A_EXTI_Line;/*外部中断线0*/
	EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
	EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Falling;
	EXTI_InitStruct.EXTI_LineCmd = DISABLE;
	EXTI_Init(&EXTI_InitStruct);
}


void Exti1_Enable()
{
    EXTI_InitTypeDef EXTI_InitStruct;
	EXTI_InitStruct.EXTI_Line = KEY_B_EXTI_Line;/*外部中断线1*/
	EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
	EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising_Falling;
	EXTI_InitStruct.EXTI_LineCmd = ENABLE;
	EXTI_Init(&EXTI_InitStruct);
}


void Exti1_Disable()
{
    EXTI_InitTypeDef EXTI_InitStruct;
	EXTI_InitStruct.EXTI_Line = KEY_B_EXTI_Line;/*外部中断线1*/
	EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
	EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising_Falling;
	EXTI_InitStruct.EXTI_LineCmd = DISABLE;
	EXTI_Init(&EXTI_InitStruct);
}

void Key_Init(void)
{
    KEY_GPIO_Init();
    EXTI_KEY_Init();
}


void Key_A_FUN(void)
{
    /*
    1.  键A控制选中位，键B修改选中位；
    2.  键A第一次按下，进入修改模式，位0为选中位；再按下，选中位右移；位3为选中位时，再按下，退出修改模式；
    3.  键B按下增加选中位上的值，满位回0，长按时每1s加1；
    */
    
    if(normal_mode == mode){
        if(key_A_num<5){
            key_A_num++;
        }
        if(1 == key_A_num){
            printf("[mode %d to " ,mode );
            mode = modify_mode;
            printf("%d]\r\n" ,mode );
        }
        //printf(" Key A down num=%d \r\n",key_A_num);
    }else if(modify_mode == mode){
        if(key_A_num<5){
            key_A_num++;
        }
        if(4 < key_A_num){
            key_A_num = 0;
            printf("[mode %d to " ,mode );
            mode = normal_mode;
            printf("%d]\r\n" ,mode );
            return ;
        }
        //printf(" Key A down num=%d \r\n",key_A_num);
    }
    printf(" Key A down num=%d \r\n",key_A_num);
    
}


void Key_B_FUN(void)
{
    if(mode == modify_mode && KEY_B == 0){
        printf("[mode %d to " ,mode );
        mode = add_mode;
        printf("%d]" ,mode );
        printf(" Key B down [bit %d]", key_A_num-1);
        
    }else if(mode == add_mode && KEY_B == 1){
        printf("[mode %d to " ,mode );
        mode = modify_mode;
        printf("%d]" ,mode );
        
        printf(" Key B up   [bit %d]\r\n", key_A_num-1);
    }

}


/*留做参考*/
#if 0
uint8_t key_state_check(void)
{
    static uint8_t key_state = 0;
    uint8_t key_return = 0;
    
    switch(key_state){
    case 0:                 // 按键初始态
        if (!KEY_B)
        {
            key_state = 1;// 键被按下，状态转换到键确认态
        }
        break;
        
    case 1:                   // 按键确认态
        if (!KEY_B)
        {
            key_return = 1;         // 按键仍按下，按键确认输出为“1”
            key_state = 2;// 状态转换到键释放态
        }
        else
        {
            key_state = 0; // 按键已抬起，转换到按键初始态
        }
        break;
        
    case 2:
        if (KEY_B)
        {
            key_state = 0;//按键已释放，转换到按键初始态
        }
        break;
    }
    return key_return;                            //返回按键值
}

//按键扫描1长按闪烁（电平判断）
int KEY_Scan1(void)
{
	static u8 key_B_down=0;//默认未按下
	
	if(KEY_B==0 && key_B_down ==0)//现在按下且之前未按下（下降沿）
	{
		delay_ms(10);//延时时间可调
		if(KEY_B==0)//确实按下
		{
			key_B_down = 1;//按下，记录状态
			return 1;//下降沿动作
		}	
	}
    
	else if(KEY_B == 1 && key_B_down ==1)//现在抬起且之前按下（上升沿）
	{
		delay_ms(10);//延时时间可调
		if(KEY_B==1)
		{
			key_B_down = 0;
			return 0;
		}		
	}
	else if(KEY_B==0 && key_B_down ==1)
	{
		delay_ms(500);
		if(KEY_B==0)//确实按下
		{
			key_B_down = 1;
			return 1;//下降沿动作
		}
	}
	return 0;//包含没按、长按、上升沿，不会阻塞
}

int KEY_Scan2(void)
{
	static u8 KEY_DOWN=0;
	if(KEY_DOWN ==0 && KEY_B==0)//现在按下且之前抬起（下降沿）
	{
		delay_ms(10);//延时时间可调
		if(KEY_B==0)//确实按下
		{
			KEY_DOWN = 1;//按下，记录状态
			return 1;//下降沿动作
		}	
	}
	else if(KEY_B == 1 && KEY_DOWN ==1)//现在抬起且之前按下（上升沿），下降沿动作时KEY_DOWN ==1一定成立，保留便于改成上升沿动作	
	{
		KEY_DOWN = 0;
//		return 1;//上升沿动作		
	}
	return 0;//包含没按、长按，不会阻塞
}
#endif


void EXTI0_IRQHandler(void)
{
    /*稍加延时增加稳定性，不加也可以，但有时会连跳*/
    delay_ms(200);
	if(EXTI_GetITStatus(KEY_A_EXTI_Line))
	{
        EXTI_ClearITPendingBit(KEY_A_EXTI_Line);
        Key_A_FUN();
		
	}
}


void EXTI1_IRQHandler(void)
{
    delay_ms(10);
    if(EXTI_GetITStatus(KEY_B_EXTI_Line))
	{   
        EXTI_ClearITPendingBit(KEY_B_EXTI_Line);
        Key_B_FUN();
    }
}


void mode_add(void)
{
    //printf("[mode %d]\r\n", mode);
    TIM_Init(10000-1,7200-1);/*用处3——长按加数定时*/
    add_flag = 1;
    while(1){
        if(add_mode == mode){
            if(add_flag){
                Time_Bit_add(key_A_num-1);
                Time_Show();
                add_flag=0;                
            }
        }else{
            break;
        }
    }
    
}


void mode_modify(void)
{
    //printf("[mode %d]\r\n", mode);
    Time_bak();
    TIM_Init(10000-1,7200-1);/*用处2——闪烁定时*/
    Exti1_Enable();
    
    while(1){
        if(modify_mode == mode){
            if(flash_flag){
                Time_Bit_flash(key_A_num-1);
            }else{
                Time_Show();
            }
        }else if(add_mode == mode){
            Exti0_Disable();
            mode_add();
            if(KEY_B == 1){
                Exti0_Enable();
            }            
            TIM_Init(10000-1,7200-1);
            flash_flag = 0;

        }else{
            break;
        }
    }
    
    key_A_num = 0;
    Time_Show();
    
    Exti1_Disable();

}


